
#include "ControlDef.h"

//ɾȫע

CEdit::CEdit(WCHAR* Name,int X,int Y,int Width)
{
	Type=CT_Edit;
	this->Name=wstrdup(Name);
	this->X=X;
	this->Y=Y;
	this->Width=Width;
	FontText=ResMgr->LoadFontR(L"-14");
	TextHeight=D2dMgr->GetFontHeight(FontText);
	this->Height=TextHeight+BodyPadding*2;
	TextAreaWidth=Width-BodyPadding*2;
	TextAreaHeight=Height-BodyPadding*2;

	Text=new WCHAR[MinAllocSize];
	BufferLen=MinAllocSize;
	TextLen=0;
	CharPosXInfo=new int[MinAllocSize+1];
	CharWidthInfo=new int[MinAllocSize+1];

	CharPosXInfo[0]=0;
	CharWidthInfo[0]=0;

	FocusStatus=FALSE;
	CaretIndex=0;
	CaretTimer=0;
	TextViewPosX=0;
	SelectState=FALSE;
	SelBegIndex=0;
	SelectIndex=0;
	SelectLen=0;
}

CEdit::~CEdit()
{
	delete[] Text;
	delete[] CharPosXInfo;
	delete[] CharWidthInfo;
	ResMgr->ReleaseFontR(FontText);
	delete[] Name;
}

void CEdit::AutoExtendBuffer(int RequiredLen)
{
	if (BufferLen<RequiredLen)
	{
		WCHAR* NewText=new WCHAR[RequiredLen*2];

		int* NewCharPosXInfo=new int[RequiredLen*2+1];
		int* NewCharWidthInfo=new int[RequiredLen*2+1];
		for (int i=0;i<TextLen;i++)
		{
			NewText[i]=Text[i];
			NewCharPosXInfo[i]=CharPosXInfo[i];
			NewCharWidthInfo[i]=CharWidthInfo[i];
		}
		NewCharPosXInfo[TextLen]=CharPosXInfo[TextLen];
		NewCharWidthInfo[TextLen]=CharWidthInfo[TextLen];
		delete[] Text;
		delete[] CharPosXInfo;
		delete[] CharWidthInfo;
		Text=NewText;
		CharPosXInfo=NewCharPosXInfo;
		CharWidthInfo=NewCharWidthInfo;
		BufferLen=RequiredLen*2;
	}
}

void CEdit::UpdateCharInfo(int StartPos)
{
	int TextWidth=0;
	if (StartPos!=0)
		TextWidth=CharPosXInfo[StartPos-1]+CharWidthInfo[StartPos-1];
	for (int i=StartPos;i<TextLen;i++)
	{
		CharPosXInfo[i]=TextWidth;
		CharWidthInfo[i]=D2dMgr->GetCharWidth(FontText,Text[i]);
		TextWidth+=CharWidthInfo[i];
	}

	CharPosXInfo[TextLen]=TextWidth;
	CharWidthInfo[TextLen]=0;
}

void CEdit::InsertText(WCHAR* NewText,int InsertNum,int InsertPos)
{
	if (InsertPos<0 || InsertPos>TextLen)
		return ;
	AutoExtendBuffer(TextLen+InsertNum);
	memmove(Text+InsertPos+InsertNum,Text+InsertPos,(TextLen-InsertPos)*sizeof(WCHAR));
	for (int i=0;i<InsertNum;i++)
		Text[InsertPos+i]=NewText[i];
	TextLen+=InsertNum;
	UpdateCharInfo(InsertPos);
}

void CEdit::DeleteText(int DeletePos,int DeleteNum)
{
	if (DeletePos<0 || DeletePos+DeleteNum>TextLen)
		return ;
	memmove(Text+DeletePos,Text+DeletePos+DeleteNum,
		(TextLen-DeletePos-DeleteNum)*sizeof(WCHAR));
	TextLen-=DeleteNum;
	UpdateCharInfo(DeletePos);
}

void CEdit::SetText(WCHAR* NewText)
{
	if (NewText==NULL)
	{
		delete[] Text;
		Text=new WCHAR[MinAllocSize];
		BufferLen=MinAllocSize;
		TextLen=0;
		CharPosXInfo=new int[MinAllocSize+1];
		CharWidthInfo=new int[MinAllocSize+1];
		CharPosXInfo[0]=0;
		CharWidthInfo[0]=0;
	}
	else
	{
		WCHAR* SafeText=FilterText(NewText);
		TextLen=wcslen(SafeText);
		AutoExtendBuffer(TextLen);
		memcpy(Text,SafeText,TextLen*sizeof(WCHAR));
		delete[] SafeText;
	}
	UpdateCharInfo(0);
}

void CEdit::ClearText()
{
	SetText(NULL);
}

int CEdit::GetTextLen()
{
	return TextLen;
}

void CEdit::GetText(WCHAR* Buffer,int MaxChar)
{
	if (Buffer!=NULL)
	{
		int WriteNum=min(TextLen,MaxChar-1);
		memcpy(Buffer,Text,WriteNum*sizeof(WCHAR));
		Buffer[WriteNum]=0;
	}
}

WCHAR* CEdit::FilterText(WCHAR* RawText)
{
	int Len=wcslen(RawText);
	WCHAR* NewText=new WCHAR[Len+1];
	int i=0;
	int Cur=0;
	while (i<Len)
	{
		if (RawText[i]>0x20)
		{
			NewText[Cur]=RawText[i];
			Cur++;
		}
		i++;
	}
	NewText[Cur]=0;
	return NewText;
}

void CEdit::Update()
{
	CaretTimer++;
}

int CEdit::CharIndexToViewPos(int CharIndex)
{
	int CharPos=CharPosXInfo[CharIndex];
	return CharPos-TextViewPosX;
}

int CEdit::ViewPosToCharIndex(int InputPos)
{
	int CharPos=InputPos+TextViewPosX;
	for (int i=0;i<TextLen;i++)
	{
		if (CharPos>=CharPosXInfo[i] && CharPos<CharPosXInfo[i]+CharWidthInfo[i])
			return i;
	}

	if (CharPos<0)
		return 0;
	return TextLen-1;
}

int CEdit::ViewPosToCaretIndex(int InputPos)
{
	int CharPos=InputPos+TextViewPosX;
	for (int i=0;i<TextLen;i++)
	{
		if (CharPos>=CharPosXInfo[i] && CharPos<CharPosXInfo[i]+CharWidthInfo[i])
		{
			if (CharPos<=CharPosXInfo[i]+CharWidthInfo[i]/2)
				return i;
			else
				return i+1;
		}
	}
	if (CharPos<0)
		return 0;
	return TextLen;
}

void CEdit::GetVisibleChar(int* FirstIndex,int* VisibleCount)
{
	*FirstIndex=-1;
	*VisibleCount=0;
	for (int i=0;i<TextLen;i++)
	{
		if (CharPosXInfo[i]+CharWidthInfo[i]>TextViewPosX && CharPosXInfo[i]<TextViewPosX+TextAreaWidth)
		{
			if (*FirstIndex==-1)
				*FirstIndex=i;
			*VisibleCount=*VisibleCount+1;		
		}
	}
	if (*FirstIndex==-1)
		*FirstIndex=0;
}

void CEdit::AlignView(int TargetPos)
{
	if (TargetPos<TextViewPosX)
		TextViewPosX=TargetPos;
	else if (TargetPos>TextViewPosX+TextAreaWidth)
		TextViewPosX=TargetPos-TextAreaWidth;
}

void CEdit::MoveCaret(int NewCaretIndex)
{
	CaretTimer=0;
	if (NewCaretIndex<0)
		NewCaretIndex=0;
	if (NewCaretIndex>TextLen)
		NewCaretIndex=TextLen;
	CaretIndex=NewCaretIndex;
	int CaretPos=CharPosXInfo[CaretIndex];
	AlignView(CaretPos);
}


void CEdit::Draw()
{
	D2dMgr->SetColor(0xFFFFFFFF);
	D2dMgr->FillRectangle(0,0,Width,Height);
	D2dMgr->SetColor(0xFF000000);
	D2dMgr->DrawRectangle(0,0,Width,Height);
	D2dMgr->SetColor(0xFF808080);
	D2dMgr->DrawRectangle(1,1,Width-2,Height-2);

	int FirstVisibleIndex;
	int VisibleLen;
	GetVisibleChar(&FirstVisibleIndex,&VisibleLen);

	D2dMgr->PushClip(TextAreaX,TextAreaY,TextAreaWidth,TextAreaHeight);
	
	if (SelectLen==0)
	{
		D2dMgr->SetColor(0xFF000000);
		D2dMgr->DrawText(Text+FirstVisibleIndex,VisibleLen,TextAreaX+CharIndexToViewPos(FirstVisibleIndex),TextAreaY,FontText);
	}
	else
	{
		int SelDrawBeginIndex=SelectIndex;
		if (SelectIndex<FirstVisibleIndex)
			SelDrawBeginIndex=FirstVisibleIndex;
		int SelDrawEndIndex=SelectIndex+SelectLen;
		if (SelDrawEndIndex>FirstVisibleIndex+VisibleLen)
			SelDrawEndIndex=FirstVisibleIndex+VisibleLen;

		int SelViewPos=CharIndexToViewPos(SelectIndex);
		int SelViewWidth=CharIndexToViewPos(SelDrawEndIndex)-SelViewPos;
		D2dMgr->SetColor(0xFFFAB455);
		D2dMgr->FillRectangle(TextAreaX+SelViewPos+1,TextAreaY,SelViewWidth,TextAreaHeight);

		int Len1=SelDrawBeginIndex-FirstVisibleIndex;
		D2dMgr->SetColor(0xFF000000);
		D2dMgr->DrawText(Text+FirstVisibleIndex,Len1,TextAreaX+CharIndexToViewPos(FirstVisibleIndex),TextAreaY,FontText);

		int Len2=SelDrawEndIndex-SelDrawBeginIndex;
		D2dMgr->SetColor(0xFFFFFFFF);
		D2dMgr->DrawText(Text+SelDrawBeginIndex,Len2,TextAreaX+CharIndexToViewPos(SelDrawBeginIndex),TextAreaY,FontText);

		int Len3=FirstVisibleIndex+VisibleLen-SelDrawEndIndex;
		D2dMgr->SetColor(0xFF000000);
		D2dMgr->DrawText(Text+SelDrawEndIndex,Len3,TextAreaX+CharIndexToViewPos(SelDrawEndIndex),TextAreaY,FontText);
	}

	D2dMgr->PopClip();

	if (FocusStatus)
	{
		if (CaretTimer%50<25)
		{
			DWORD CaretColor=0xFF000000;
			D2dMgr->SetColor(CaretColor);
			int CaretX=CharIndexToViewPos(CaretIndex);
			D2dMgr->DrawLine(TextAreaX+CaretX+1,TextAreaY,TextAreaX+CaretX+1,TextAreaY+TextHeight,1);
		}
	}
}

void CEdit::TextCommandSelectAll()
{
	SelectIndex=0;
	SelectLen=TextLen;
	MoveCaret(TextLen+1);
}

void CEdit::TextCommandDelete()
{
	DeleteText(SelectIndex,SelectLen);
	if (CaretIndex>SelectIndex && CaretIndex<=SelectIndex+SelectLen)
		MoveCaret(SelectIndex);
	else if (CaretIndex>SelectIndex+SelectLen)
		MoveCaret(CaretIndex-SelectLen);
	SelectLen=0;
}

void CEdit::TextCommandCopy()
{
	if (SelectLen!=0)
		CopyTextToClipboard(D2dMgr->hWnd,Text+SelectIndex,SelectLen);
}

void CEdit::TextCommandPaste()
{
	WCHAR Buf[1024];
	TextCommandDelete();
	PasteTextFromClipboard(D2dMgr->hWnd,Buf,1024);
	WCHAR* SafeText=FilterText(Buf);
	int InputLen=wcslen(SafeText);
	InsertText(SafeText,InputLen,CaretIndex);
	MoveCaret(CaretIndex+InputLen);
	delete[] SafeText;
}

int CEdit::Notify(UIEvent_t UIEvent,PVOID Param1,PVOID Param2)
{
	if (UIEvent==EvtQueryImmPos)
	{
		if (FocusStatus)
		{
			int* xptr=(int*)Param1;
			int* yptr=(int*)Param2;
			*xptr=TextAreaX+CharIndexToViewPos(CaretIndex);
			*yptr=TextAreaY;
			return 1;
		}
	}
	else if (UIEvent==EvtKeyInput)
	{
		if (SelectLen!=0)
			TextCommandDelete();
		SelectLen=0;
		WCHAR* InputText=(WCHAR*)Param1;
		int InputLen=(int)Param2;
		InsertText(InputText,InputLen,CaretIndex);
		MoveCaret(CaretIndex+InputLen);
	}
	else if (UIEvent==EvtKeyDown)
	{	
		int InputKey=(int)Param1;
		if (UiMgr->IsCtrlKeyDown())
		{
			if (InputKey=='A')
			{
				TextCommandSelectAll();
			}
			else if (InputKey=='C')
			{
				TextCommandCopy();
			}
			else if (InputKey=='V')
			{
				TextCommandPaste();
			}
			else if (InputKey=='X')
			{
				TextCommandCopy();
				TextCommandDelete();
			}
		}
		else
		{
			if (InputKey==VK_LEFT)
			{
				SelectLen=0;
				MoveCaret(CaretIndex-1);
			}
			else if (InputKey==VK_RIGHT)
			{
				SelectLen=0;
				MoveCaret(CaretIndex+1);
			}
			else if (InputKey==VK_BACK)
			{
				if (SelectLen==0 && CaretIndex>0)
				{
					DeleteText(CaretIndex-1,1);
					MoveCaret(CaretIndex-1);
				}
				else
				{
					TextCommandDelete();
				}
			}
			else if (InputKey==VK_DELETE)
			{
				TextCommandDelete();
			}
			else if (InputKey==VK_RETURN)
			{
				UiMgr->BlurControl(this);
			}
		}
	}
	else if (UIEvent==EvtMouseDown)
	{
		int InputX=(int)Param1-TextAreaX;
		SelBegIndex=ViewPosToCaretIndex(InputX);
		MoveCaret(SelBegIndex);
		SelectLen=0;
		SelectState=TRUE;
	}
	else if (UIEvent==EvtMouseUp)
	{
		SelectState=FALSE;
	}
	else if (UIEvent==EvtMouseMove)
	{
		int InputX=(int)Param1-TextAreaX;
		if (SelectState)
		{
			int SelEndIndex=ViewPosToCaretIndex(InputX);
			MoveCaret(SelEndIndex);
			SelectLen=0;
			if (SelBegIndex<SelEndIndex)
			{
				SelectIndex=SelBegIndex;
				SelectLen=SelEndIndex-SelBegIndex;
			}
			else if (SelBegIndex>SelEndIndex)
			{
				SelectIndex=SelEndIndex;
				SelectLen=SelBegIndex-SelEndIndex;
			}
		}
	}
	else if (UIEvent==EvtFocus)
	{
		FocusStatus=TRUE;
		CaretTimer=0;
	}
	else if (UIEvent==EvtBlur)
	{
		FocusStatus=FALSE;
		SelectLen=0;
		if (this->EventHandler!=NULL)
			EventHandler(this,EvtEditChange,(PVOID)Text,(PVOID)TextLen);
	}
	return 0;
}




